package com.deya.iot.poi;

import cn.afterturn.easypoi.entity.BaseTypeConstants;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelCollection;
import cn.afterturn.easypoi.excel.annotation.ExcelEntity;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelCollectionParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelImportEntity;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.excel.imports.CellValueService;
import cn.afterturn.easypoi.excel.imports.ExcelImportService;
import cn.afterturn.easypoi.excel.imports.base.ImportBaseService;
import cn.afterturn.easypoi.excel.imports.recursive.ExcelImportForkJoinWork;
import cn.afterturn.easypoi.exception.excel.ExcelImportException;
import cn.afterturn.easypoi.exception.excel.enums.ExcelImportEnum;
import cn.afterturn.easypoi.handler.inter.IExcelDataModel;
import cn.afterturn.easypoi.handler.inter.IExcelModel;
import cn.afterturn.easypoi.util.PoiCellUtil;
import cn.afterturn.easypoi.util.PoiPublicUtil;
import cn.afterturn.easypoi.util.PoiReflectorUtil;
import cn.afterturn.easypoi.util.PoiValidationUtil;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.concurrent.ForkJoinPool;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DeyaExcelImportService extends ExcelImportService {
    private static final Logger LOGGER = LoggerFactory.getLogger(cn.afterturn.easypoi.excel.imports.ExcelImportService.class);
    private CellValueService cellValueServer = new CellValueService();
    private boolean verifyFail = false;
    private CellStyle errorCellStyle;
    private List<Row> successRow = new ArrayList();
    private List<Row> failRow = new ArrayList();
    private List failCollection = new ArrayList();

    public DeyaExcelImportService() {
    }

    public void addListContinue(Object object, ExcelCollectionParams param, Row row, Map<Integer, String> titlemap,
                                String targetId, Map<String, PictureData> pictures,
                                ImportParams params, StringBuilder errorMsg,Short cellStart) throws Exception {
        this.addListContinue(object, param, row, titlemap, targetId, pictures, params, errorMsg,cellStart,
                new HashMap<String,Boolean>(param.getExcelParams().size()));
    }
    public void addListContinue(Object object, ExcelCollectionParams param, Row row, Map<Integer, String> titlemap,
                                String targetId, Map<String, PictureData> pictures,
                                ImportParams params, StringBuilder errorMsg,Short cellStart,Map<String,Boolean> usedMap) throws Exception {
        Collection collection = (Collection) PoiReflectorUtil.fromCache(object.getClass()).getValue(object, param.getName());
        Object entity = PoiPublicUtil.createObject(param.getType(), targetId);
        if (entity instanceof IExcelDataModel) {
            ((IExcelDataModel) entity).setRowNum(row.getRowNum());
        }
        boolean isUsed = false;
        boolean isRealUsed = false;//值不为null
        boolean mergeEmptyValue = true;
        //对map中的属性排序 短的排前面
        List<Map.Entry<Integer, String>> list = new ArrayList<>(titlemap.entrySet());
        list.sort((o1, o2) -> Integer.valueOf(o1.getValue().split("_").length).compareTo(o2.getValue().split("_").length));

        //usedMap用于递归时省去上一层
//        Map<String,Boolean> usedMap = new HashMap<>(list.size());
//        for (int i = row.getFirstCellNum(); i < titlemap.size(); ++i) {
        for (int i = cellStart; i < list.size(); ++i) {
            Cell cell = row.getCell(list.get(i).getKey());
            String titleString = (String) list.get(i).getValue();

            if (param.getExcelParams().containsKey(titleString) &&
                    ( usedMap.get(titleString)==null || !usedMap.get(titleString))) {
//                //如果value不同 重新new一个
//                Object value = this.cellValueServer.getValue(params.getDataHandler(), entity, cell, param.getExcelParams(), titleString, params.getDictHandler());

                ExcelImportEntity importEntity = (ExcelImportEntity) param.getExcelParams().get(titleString);
                if(importEntity.getCollectionName()!=null && !importEntity.getCollectionName()
                    .endsWith(param.getName()) ) {//所有的集合属性字段不能同名 不然这里会混乱

                    String collectionName = importEntity.getCollectionName();
                    String[] collectionNames = collectionName.split("_");
                    String lastCollectionName = collectionNames[collectionNames.length-1];

                    ExcelImportEntity importEntityCollect = new ExcelImportEntity();
                    importEntityCollect.setMethod(
                            PoiReflectorUtil.fromCache(
                                param.getType()).getSetMethod(lastCollectionName));

                    Collection collection1 = (Collection) PoiReflectorUtil.fromCache(
                            param.getType()).getValue(entity, lastCollectionName);
                    this.setValues(importEntityCollect, entity, collection1);

                    Class clazz = Class.forName(importEntity.getClassType());
//                    Object object1 = PoiPublicUtil.createObject( clazz, targetId);
                    //处理多重嵌套集合
                    ExcelCollectionParams collectionParams = new ExcelCollectionParams();
                    collectionParams.setName(lastCollectionName);
                    collectionParams.setType(clazz);
                    collectionParams.setExcelParams(param.getExcelParams());
                    this.addListContinue(entity,collectionParams,row,titlemap,targetId,  pictures,   params,   errorMsg,(short)i,usedMap);

                }else{
                    boolean needMerge = importEntity.getEnumImportMethod()!=null&&importEntity.getEnumImportMethod().startsWith("merge_")?
                            Boolean.valueOf(importEntity.getEnumImportMethod().replace("merge_","")):false;
                    boolean haveValue = false;
                    if (importEntity.getType() == BaseTypeConstants.IMAGE_TYPE) {
                        String picId = row.getRowNum() + "_" + list.get(i).getKey();
                        this.saveImage(entity, picId, param.getExcelParams(), titleString, pictures, params);
                        if (pictures != null) {
                            PictureData image = (PictureData) pictures.get(picId);
                            if(image!=null){
                                isRealUsed = true;haveValue = true;
                            }
                        }
                    } else {
                        try {
                            this.saveFieldValue(params, entity, cell, param.getExcelParams(), titleString, row);
                        } catch (ExcelImportException var17) {
                            if (params.isNeedVerify() && ExcelImportEnum.GET_VALUE_ERROR.equals(var17.getType())) {
                                errorMsg.append(" ").append(titleString).append(ExcelImportEnum.GET_VALUE_ERROR.getMsg());
                            }
                        }
                        Object value = this.cellValueServer.getValue(params.getDataHandler(), entity, cell, param.getExcelParams(), titleString, params.getDictHandler());
                        if(value != null){
                            isRealUsed = true;
                        }
                        if(value != null && !value.toString().equals("")){
                            haveValue = true;
                        }
                    }
                    if(needMerge && !haveValue && collection.size()>0){
//                        mergeEmptyValue = true;
                        Object[] collectionArr = collection.toArray();
                        entity = collectionArr[collectionArr.length - 1];
                    }

                    isUsed = true;
                    usedMap.put(titleString,isUsed);
                    usedMap.put(importEntity.getCollectionName()+"_"+titleString+"_isrealused",isRealUsed);
                }
            }
        }
        //只要有值就需要添加到集合 否则忽略
        Boolean atLeastOneRealUesd = false;
        for(String key :usedMap.keySet()){
            if(key.contains(param.getName()+"_") && key.endsWith("_isrealused") && usedMap.get(key) != null && usedMap.get(key)){
                atLeastOneRealUesd = true;
            }
        }
        Object lastEntity = null;
        if(  collection.size()>0) {
            Object[] collectionArr = collection.toArray();
            lastEntity = collectionArr[collectionArr.length - 1];
        }
        if ( atLeastOneRealUesd && (lastEntity==null||entity!=lastEntity)) {//
            collection.add(entity);
        }

    }

    private String getKeyValue(Cell cell) {
        Object obj = PoiCellUtil.getCellValue(cell);
        return obj == null ? null : obj.toString().trim();
    }

    private String getSaveUrl(ExcelImportEntity excelImportEntity, Object object) throws Exception {
        String url = "";
        if ("/excel/upload/img".equals(excelImportEntity.getSaveUrl())) {
            if (excelImportEntity.getMethods() != null && excelImportEntity.getMethods().size() > 0) {
                object = this.getFieldBySomeMethod(excelImportEntity.getMethods(), object);
            }

            url = object.getClass().getName().split("\\.")[object.getClass().getName().split("\\.").length - 1];
            return excelImportEntity.getSaveUrl() + File.separator + url;
        } else {
            return excelImportEntity.getSaveUrl();
        }
    }

    private <T> List<T> importExcel(Collection<T> result, Sheet sheet, Class<?> pojoClass, ImportParams params, Map<String, PictureData> pictures) throws Exception {
        List collection = new ArrayList();
        Map<String, ExcelImportEntity> excelParams = new HashMap();//处理单独的
        List<ExcelCollectionParams> excelCollection = new ArrayList();//处理嵌套的
        String targetId = null;
        this.i18nHandler = params.getI18nHandler();
        boolean isMap = Map.class.equals(pojoClass);
        if (!isMap) {
            Field[] fileds = PoiPublicUtil.getClassFields(pojoClass);
            ExcelTarget etarget = (ExcelTarget) pojoClass.getAnnotation(ExcelTarget.class);
            if (etarget != null) {
                targetId = etarget.value();
            }
            //获取所有excel注解的field相关
            this.getAllExcelField(targetId, fileds, excelParams, excelCollection, pojoClass, (List) null, (ExcelEntity) null);
        }

        Iterator<Row> rows = sheet.rowIterator();

        for (int j = 0; j < params.getTitleRows(); ++j) {
            rows.next();
        }

        Map<Integer, String> titlemap = this.getTitleMap(rows, params, excelCollection, excelParams);
        this.checkIsValidTemplate(titlemap, excelParams, params, excelCollection);
        Row row = null;
        Object object = null;
        int readRow = 1;

        int endRow;
        for (endRow = 0; endRow < params.getStartRows(); ++endRow) {
            rows.next();
        }

        if (excelCollection.size() > 0 && params.getKeyIndex() == null) {
            params.setKeyIndex(0);
        }

        endRow = sheet.getLastRowNum() - params.getLastOfInvalidRow();
        if (params.getReadRows() > 0) {
            endRow = Math.min(params.getReadRows(), endRow);
        }

        if (params.isConcurrentTask()) {
            ForkJoinPool forkJoinPool = new ForkJoinPool();
            ExcelImportForkJoinWork task = new ExcelImportForkJoinWork(params.getStartRows() + params.getHeadRows() + params.getTitleRows(), endRow, sheet, params, pojoClass, this, targetId, titlemap, excelParams);
            ExcelImportResult forkJoinResult = (ExcelImportResult) forkJoinPool.invoke(task);
            collection = forkJoinResult.getList();
            this.failCollection = forkJoinResult.getFailList();
            return (List) collection;
        } else {
            while (true) {
                do {
                    if (!rows.hasNext()) {
                        return (List) collection;
                    }

                    row = (Row) rows.next();
                    if (row.getRowNum() > endRow) {
                        return (List) collection;
                    }
                } while (row.getLastCellNum() < 0);

                if (isMap && object != null) {
                    ((Map) object).put("excelRowNum", row.getRowNum());
                }
                //一下条件处理同一row其他collection属性  object != null
                StringBuilder errorMsg = new StringBuilder();
                if (params.getKeyIndex() != null && (row.getCell(params.getKeyIndex()) == null || StringUtils.isEmpty(this.getKeyValue(row.getCell(params.getKeyIndex())))) && object != null) {
                    Iterator var32 = excelCollection.iterator();

                    while (var32.hasNext()) {
                        ExcelCollectionParams param = (ExcelCollectionParams) var32.next();
                        this.addListContinue(object, param, row, titlemap, targetId, pictures, params, errorMsg,row.getFirstCellNum());
                    }
                } else {
                    object = PoiPublicUtil.createObject(pojoClass, targetId);

                     try {
                        Set<Integer> keys = titlemap.keySet();
                        Iterator var20 = keys.iterator();

                        label123:
                        while (true) {
                            while (true) {
                                Integer cn;
                                Cell cell;
                                String titleString;
                                do {
                                    if (!var20.hasNext()) {
                                        if (object instanceof IExcelDataModel) {
                                            ((IExcelDataModel) object).setRowNum(row.getRowNum());
                                        }

                                        var20 = excelCollection.iterator();

                                        while (var20.hasNext()) {
                                            ExcelCollectionParams param = (ExcelCollectionParams) var20.next();
                                            this.addListContinue(object, param, row, titlemap, targetId, pictures, params, errorMsg,row.getFirstCellNum());
                                        }

                                        if (this.verifyingDataValidity(object, row, params, isMap, errorMsg)) {
                                            ((List) collection).add(object);
                                        } else {
                                            this.failCollection.add(object);
                                        }
                                        break label123;
                                    }

                                    cn = (Integer) var20.next();
                                    cell = row.getCell(cn);
                                    titleString = (String) titlemap.get(cn);
                                } while (!excelParams.containsKey(titleString) && !isMap);

                                if (excelParams.get(titleString) != null && ((ExcelImportEntity) excelParams.get(titleString)).getType() == BaseTypeConstants.IMAGE_TYPE) {
                                    String picId = row.getRowNum() + "_" + cn;
                                    this.saveImage(object, picId, excelParams, titleString, pictures, params);
                                } else {
                                    try {
                                        this.saveFieldValue(params, object, cell, excelParams, titleString, row);
                                    } catch (ExcelImportException var25) {
                                        if (params.isNeedVerify() && ExcelImportEnum.GET_VALUE_ERROR.equals(var25.getType())) {
                                            errorMsg.append(" ").append(titleString).append(ExcelImportEnum.GET_VALUE_ERROR.getMsg());
                                        }
                                    }
                                }
                            }
                        }
                    } catch (ExcelImportException var26) {
                        LOGGER.error("excel import error , row num:{},obj:{}", readRow, ReflectionToStringBuilder.toString(object));
                        if (!var26.getType().equals(ExcelImportEnum.VERIFY_ERROR)) {
                            throw new ExcelImportException(var26.getType(), var26);
                        }
                    } catch (Exception var27) {
                        LOGGER.error("excel import error , row num:{},obj:{}", readRow, ReflectionToStringBuilder.toString(object));
                        throw new RuntimeException(var27);
                    }
                }

                ++readRow;
            }
        }
    }

    public boolean verifyingDataValidity(Object object, Row row, ImportParams params, boolean isMap, StringBuilder fieldErrorMsg) {
        boolean isAdd = true;
        Cell cell = null;
        IExcelModel model;
        if (params.isNeedVerify()) {
            String errorMsg = PoiValidationUtil.validation(object, params.getVerifyGroup());
            if (StringUtils.isNotEmpty(errorMsg)) {
                cell = row.createCell(row.getLastCellNum());
                cell.setCellValue(errorMsg);
                if (object instanceof IExcelModel) {
                    model = (IExcelModel) object;
                    model.setErrorMsg(errorMsg);
                }

                isAdd = false;
                this.verifyFail = true;
            }
        }

        if (params.getVerifyHandler() != null) {
            ExcelVerifyHandlerResult result = params.getVerifyHandler().verifyHandler(object);
            if (!result.isSuccess()) {
                if (cell == null) {
                    cell = row.createCell(row.getLastCellNum());
                }

                cell.setCellValue((StringUtils.isNoneBlank(new CharSequence[]{cell.getStringCellValue()}) ? cell.getStringCellValue() + "," : "") + result.getMsg());
                if (object instanceof IExcelModel) {
                    model = (IExcelModel) object;
                    model.setErrorMsg((StringUtils.isNoneBlank(new CharSequence[]{model.getErrorMsg()}) ? model.getErrorMsg() + "," : "") + result.getMsg());
                }

                isAdd = false;
                this.verifyFail = true;
            }
        }

        if ((params.isNeedVerify() || params.getVerifyHandler() != null) && fieldErrorMsg.length() > 0) {
            if (object instanceof IExcelModel) {
                IExcelModel model1 = (IExcelModel) object;
                model1.setErrorMsg((StringUtils.isNoneBlank(new CharSequence[]{model1.getErrorMsg()}) ? model1.getErrorMsg() + "," : "") + fieldErrorMsg.toString());
            }

            if (cell == null) {
                cell = row.createCell(row.getLastCellNum());
            }

            cell.setCellValue((StringUtils.isNoneBlank(new CharSequence[]{cell.getStringCellValue()}) ? cell.getStringCellValue() + "," : "") + fieldErrorMsg.toString());
            isAdd = false;
            this.verifyFail = true;
        }

        if (cell != null) {
            cell.setCellStyle(this.errorCellStyle);
            this.failRow.add(row);
            if (isMap) {
                ((Map) object).put("excelErrorMsg", cell.getStringCellValue());
            }
        } else {
            this.successRow.add(row);
        }

        return isAdd;
    }

    boolean containStartCollectioinName(ExcelCollectionParams collectionParams,String collectionName,String value){
        for(String key :collectionParams.getExcelParams().keySet()) {
            if(key.startsWith(collectionName + "_" + value)){
                return true;
            }
        }
        return false;
    }
    //
    private Map<Integer, String> getTitleMap(Iterator<Row> rows, ImportParams params, List<ExcelCollectionParams> excelCollection, Map<String, ExcelImportEntity> excelParams) {
        Map<Integer, String> titlemap = new LinkedHashMap();
        String collectionName = null;
        ExcelCollectionParams collectionParams = null;
        Row row = null;

        String value;
        label56:
        for (int j = 0; j < params.getHeadRows(); ++j) {
            row = (Row) rows.next();
            if (row != null) {
                Iterator cellTitle = row.cellIterator();

                while (true) {
                    int i;
                    do {
                        if (!cellTitle.hasNext()) {
                            continue label56;
                        }

                        Cell cell = (Cell) cellTitle.next();
                        value = this.getKeyValue(cell);
                        value = value.replace("\n", "");
                        i = cell.getColumnIndex();
                    } while (!StringUtils.isNotEmpty(value));

                    if (titlemap.containsKey(i)) {
                        collectionName = (String) titlemap.get(i);
                        if(collectionName.indexOf("_")>0){
                            collectionParams = this.getCollectionParams(excelCollection, collectionName.split("_")[0]);
                        }else if(this.getCollectionParams(excelCollection, collectionName)!=null){
                            collectionParams = this.getCollectionParams(excelCollection, collectionName);
                        }
                        titlemap.put(i, collectionName + "_" + value);
                    } else if (StringUtils.isNotEmpty(collectionName) && collectionParams != null && containStartCollectioinName(collectionParams,collectionName,value)) {
                        titlemap.put(i, collectionName + "_" + value);
                    } else {
                        collectionName = null;
                        collectionParams = null;
                    }

                    if (StringUtils.isEmpty(collectionName)) {
                        titlemap.put(i, value);
                    }
                }
            }
        }

        Set<String> keys = excelParams.keySet();
        Iterator var15 = keys.iterator();

        while (var15.hasNext()) {
            value = (String) var15.next();
            if (value.startsWith("FIXED_")) {
                String[] arr = value.split("_");
                titlemap.put(Integer.parseInt(arr[1]), value);
            }
        }

        return titlemap;
    }

    private ExcelCollectionParams getCollectionParams(List<ExcelCollectionParams> excelCollection, String collectionName) {
        Iterator var3 = excelCollection.iterator();

        ExcelCollectionParams excelCollectionParams;
        do {
            if (!var3.hasNext()) {
                return null;
            }

            excelCollectionParams = (ExcelCollectionParams) var3.next();
        } while (!collectionName.equals(excelCollectionParams.getExcelName()));

        return excelCollectionParams;
    }

    public ExcelImportResult importExcelByIs(InputStream inputstream, Class<?> pojoClass, ImportParams params, boolean needMore) throws Exception {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Excel import start ,class is {}", pojoClass);
        }

        List<T> result = new ArrayList();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        ExcelImportResult importResult;
        try {
            byte[] buffer = new byte[1024];

            int len;
            while ((len = inputstream.read(buffer)) > -1) {
                baos.write(buffer, 0, len);
            }

            baos.flush();
            InputStream userIs = new ByteArrayInputStream(baos.toByteArray());
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Excel clone success");
            }

            Workbook book = WorkbookFactory.create(userIs);
            boolean isXSSFWorkbook = !(book instanceof HSSFWorkbook);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Workbook create success");
            }

            importResult = new ExcelImportResult();
            this.createErrorCellStyle(book);
            int i = params.getStartSheetIndex();

            while (true) {
                if (i >= params.getStartSheetIndex() + params.getSheetNum()) {
                    if (params.isNeedSave()) {
                        this.saveThisExcel(params, pojoClass, isXSSFWorkbook, book);
                    }

                    importResult.setList(result);
                    if (!needMore) {
                        break;
                    }

                    ByteArrayInputStream successIs = new ByteArrayInputStream(baos.toByteArray());

                    try {
                        Workbook successBook = WorkbookFactory.create(successIs);
                        if (params.isVerifyFileSplit()) {
                            importResult.setWorkbook(this.removeSuperfluousRows(successBook, this.failRow, params));
                            importResult.setFailWorkbook(this.removeSuperfluousRows(book, this.successRow, params));
                        } else {
                            importResult.setWorkbook(book);
                        }

                        importResult.setFailList(this.failCollection);
                        importResult.setVerifyFail(this.verifyFail);
                        break;
                    } finally {
                        successIs.close();
                    }
                }

                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(" start to read excel by is ,startTime is {}", new Date());
                }

                Map pictures;
                if (isXSSFWorkbook) {
                    pictures = PoiPublicUtil.getSheetPictrues07((XSSFSheet) book.getSheetAt(i), (XSSFWorkbook) book);
                } else {
                    pictures = PoiPublicUtil.getSheetPictrues03((HSSFSheet) book.getSheetAt(i), (HSSFWorkbook) book);
                }

                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(" end to read excel by is ,endTime is {}", new Date());
                }

                result.addAll(this.importExcel(result, book.getSheetAt(i), pojoClass, params, pictures));
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug(" end to read excel list by sheet ,endTime is {}", new Date());
                }

                if (params.isReadSingleCell()) {
                    this.readSingleCell(importResult, book.getSheetAt(i), params);
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug(" read Key-Value ,endTime is {}", System.currentTimeMillis());
                    }
                }

                ++i;
            }
        } finally {
            IOUtils.closeQuietly(baos);
        }

        return importResult;
    }

    private Workbook removeSuperfluousRows(Workbook book, List<Row> rowList, ImportParams params) {
        for (int i = params.getStartSheetIndex(); i < params.getStartSheetIndex() + params.getSheetNum(); ++i) {
            for (int j = rowList.size() - 1; j >= 0; --j) {
                if (((Row) rowList.get(j)).getRowNum() < ((Row) rowList.get(j)).getSheet().getLastRowNum()) {
                    book.getSheetAt(i).shiftRows(((Row) rowList.get(j)).getRowNum() + 1, ((Row) rowList.get(j)).getSheet().getLastRowNum(), -1);
                } else if (((Row) rowList.get(j)).getRowNum() == ((Row) rowList.get(j)).getSheet().getLastRowNum()) {
                    book.getSheetAt(i).createRow(((Row) rowList.get(j)).getRowNum() + 1);
                    book.getSheetAt(i).shiftRows(((Row) rowList.get(j)).getRowNum() + 1, ((Row) rowList.get(j)).getSheet().getLastRowNum() + 1, -1);
                }
            }
        }

        return book;
    }

    private void readSingleCell(ExcelImportResult result, Sheet sheet, ImportParams params) {
        if (result.getMap() == null) {
            result.setMap(new HashMap());
        }

        int i;
        for (i = 0; i < params.getTitleRows() + params.getHeadRows() + params.getStartRows(); ++i) {
            this.getSingleCellValueForRow(result, sheet.getRow(i), params);
        }

        for (i = sheet.getLastRowNum() - params.getLastOfInvalidRow(); i < sheet.getLastRowNum(); ++i) {
            this.getSingleCellValueForRow(result, sheet.getRow(i), params);
        }

    }

    private void getSingleCellValueForRow(ExcelImportResult result, Row row, ImportParams params) {
        int j = row.getFirstCellNum();

        for (short le = row.getLastCellNum(); j < le; ++j) {
            String text = PoiCellUtil.getCellValue(row.getCell(j));
            if (StringUtils.isNoneBlank(new CharSequence[]{text}) && text.endsWith(params.getKeyMark())) {
                if (result.getMap().containsKey(text)) {
                    if (result.getMap().get(text) instanceof String) {
                        List<String> list = new ArrayList();
                        list.add((String) result.getMap().get(text));
                        result.getMap().put(text, list);
                    }

                    List var10000 = (List) result.getMap().get(text);
                    ++j;
                    var10000.add(PoiCellUtil.getCellValue(row.getCell(j)));
                } else {
                    Map var8 = result.getMap();
                    ++j;
                    var8.put(text, PoiCellUtil.getCellValue(row.getCell(j)));
                }
            }
        }

    }

    private void checkIsValidTemplate(Map<Integer, String> titlemap, Map<String, ExcelImportEntity> excelParams, ImportParams params, List<ExcelCollectionParams> excelCollection) {
        Iterator var6;
        int i1;
        if (params.getImportFields() != null) {
            int i;
            if (params.isNeedCheckOrder()) {
                if (params.getImportFields().length != titlemap.size()) {
                    LOGGER.error("excel列顺序不一致");
                    throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                }

                i = 0;
                var6 = titlemap.values().iterator();

                while (var6.hasNext()) {
                    String title = (String) var6.next();
                    if (!StringUtils.equals(title, params.getImportFields()[i++])) {
                        LOGGER.error("excel列顺序不一致");
                        throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                    }
                }
            } else {
                i = 0;

                for (i = params.getImportFields().length; i < i; ++i) {
                    if (!titlemap.containsValue(params.getImportFields()[i])) {
                        throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                    }
                }
            }
        } else {
            Collection<ExcelImportEntity> collection = excelParams.values();
            var6 = collection.iterator();

            while (var6.hasNext()) {
                ExcelImportEntity excelImportEntity = (ExcelImportEntity) var6.next();
                if (excelImportEntity.isImportField() && !titlemap.containsValue(excelImportEntity.getName())) {
                    LOGGER.error(excelImportEntity.getName() + "必须有,但是没找到");
                    throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                }
            }

            i1 = 0;

            for (int le = excelCollection.size(); i1 < le; ++i1) {
                ExcelCollectionParams collectionparams = (ExcelCollectionParams) excelCollection.get(i1);
                collection = collectionparams.getExcelParams().values();
                Iterator var9 = collection.iterator();

                while (var9.hasNext()) {
                    ExcelImportEntity excelImportEntity = (ExcelImportEntity) var9.next();
                    if (excelImportEntity.isImportField() && !titlemap.containsValue(collectionparams.getExcelName() + "_" + excelImportEntity.getName())) {
                        throw new ExcelImportException(ExcelImportEnum.IS_NOT_A_VALID_TEMPLATE);
                    }
                }
            }
        }

    }

    public void saveFieldValue(ImportParams params, Object object, Cell cell, Map<String, ExcelImportEntity> excelParams, String titleString, Row row) throws Exception {
        Object value = this.cellValueServer.getValue(params.getDataHandler(), object, cell, excelParams, titleString, params.getDictHandler());
        if (object instanceof Map) {
            if (params.getDataHandler() != null) {
                params.getDataHandler().setMapValue((Map) object, titleString, value);
            } else {
                ((Map) object).put(titleString, value);
            }
        } else {
            this.setValues((ExcelImportEntity) excelParams.get(titleString), object, value);
        }

    }

    private void saveImage(Object object, String picId, Map<String, ExcelImportEntity> excelParams, String titleString, Map<String, PictureData> pictures, ImportParams params) throws Exception {
        if (pictures != null) {
            PictureData image = (PictureData) pictures.get(picId);
            if (image != null) {
                byte[] data = image.getData();
                String fileName = "pic" + Math.round(Math.random() * 1.0E11D);
                fileName = fileName + "." + PoiPublicUtil.getFileExtendName(data);
                if (((ExcelImportEntity) excelParams.get(titleString)).getSaveType() == 1) {
                    String path = this.getSaveUrl((ExcelImportEntity) excelParams.get(titleString), object);
                    File savefile = new File(path);
                    if (!savefile.exists()) {
                        savefile.mkdirs();
                    }

                    savefile = new File(path + File.separator + fileName);
                    FileOutputStream fos = new FileOutputStream(savefile);

                    try {
                        fos.write(data);
                    } finally {
                        IOUtils.closeQuietly(fos);
                    }

                    this.setValues((ExcelImportEntity) excelParams.get(titleString), object, this.getSaveUrl((ExcelImportEntity) excelParams.get(titleString), object) + File.separator + fileName);
                } else {
                    this.setValues((ExcelImportEntity) excelParams.get(titleString), object, data);
                }

            }
        }
    }

    private void createErrorCellStyle(Workbook workbook) {
        this.errorCellStyle = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setColor((short) 10);
        this.errorCellStyle.setFont(font);
    }

    public void getAllExcelField(String targetId, Field[] fields, Map<String, ExcelImportEntity> excelParams, List<ExcelCollectionParams> excelCollection, Class<?> pojoClass, List<Method> getMethods, ExcelEntity excelEntityAnn) throws Exception {
        ExcelImportEntity excelEntity = null;

        for(int i = 0; i < fields.length; ++i) {
            Field field = fields[i];
            if (!PoiPublicUtil.isNotUserExcelUserThis((List)null, field, targetId)) {
                if (PoiPublicUtil.isCollection(field.getType())) {
                    ExcelCollection excel = (ExcelCollection)field.getAnnotation(ExcelCollection.class);
                    ExcelCollectionParams collection = new ExcelCollectionParams();
                    collection.setName(field.getName());
                    Map<String, ExcelImportEntity> temp = new HashMap();
                    ParameterizedType pt = (ParameterizedType)field.getGenericType();
                    Class<?> clz = (Class)pt.getActualTypeArguments()[0];
                    collection.setType(clz);
                    String collectionName = collection.getName();
                    String collectionNameParent = null;
                    if(temp.get("collectionName")!=null && temp.get("collectionName").getCollectionName()!=null ){
                        collectionNameParent = temp.get("collectionName").getCollectionName();
                        collectionName = temp.get("collectionName").getCollectionName()+"_"+collectionName;
                    }
                    excelEntity = new ExcelImportEntity();
                    excelEntity.setCollectionName(collectionName);
                    temp.put("collectionName",excelEntity);
                    this.getExcelFieldList(StringUtils.isNotEmpty(excel.id()) ? excel.id() : targetId, PoiPublicUtil.getClassFields(clz), clz, temp, (List)null,excelCollection);
                    if(temp.get("collectionName")!=null && temp.get("collectionName").getCollectionName()!=null
                            && temp.get("collectionName").getCollectionName().indexOf("_")>0){
                        excelEntity.setCollectionName(collectionNameParent);
                        temp.put("collectionName",excelEntity);
                    }else{
                    }
                    collection.setExcelParams(temp);
                    collection.setExcelName(PoiPublicUtil.getValueByTargetId(((ExcelCollection)field.getAnnotation(ExcelCollection.class)).name(), targetId, (String)null));
                    this.additionalCollectionName(collection);
                    if(collectionNameParent==null){
                        temp.remove("collectionName");
                        for(String key :collection.getExcelParams().keySet()){
                            ExcelImportEntity importEntity = collection.getExcelParams().get(key);
                            importEntity.setCollectionName(importEntity.getGroupName());
                            importEntity.setGroupName(null);
                        }
                        excelCollection.add(collection);
                    }
                } else if (!PoiPublicUtil.isJavaClass(field) && !field.getType().isEnum()) {
                    List<Method> newMethods = new ArrayList();
                    if (getMethods != null) {
                        newMethods.addAll(getMethods);
                    }

                    newMethods.add(PoiReflectorUtil.fromCache(pojoClass).getGetMethod(field.getName()));
                    ExcelEntity excel = (ExcelEntity)field.getAnnotation(ExcelEntity.class);
                    if (excel.show() && StringUtils.isEmpty(excel.name())) {
                        throw new ExcelImportException("if use ExcelEntity ,name mus has value ,data: " + ReflectionToStringBuilder.toString(excel), ExcelImportEnum.PARAMETER_ERROR);
                    }

                    this.getAllExcelField(StringUtils.isNotEmpty(excel.id()) ? excel.id() : targetId, PoiPublicUtil.getClassFields(field.getType()), excelParams, excelCollection, field.getType(), newMethods, excel);
                } else {
                    this.addEntityToMap(targetId, field, (ExcelImportEntity)excelEntity, pojoClass, getMethods, excelParams, excelEntityAnn);
                }
            }
        }

    }
    //temp 存放excel注解解析结果
    public void getExcelFieldList(String targetId, Field[] fields, Class<?> pojoClass, Map<String, ExcelImportEntity> temp, List<Method> getMethods, List<ExcelCollectionParams> excelCollection) throws Exception {
        ExcelImportEntity excelEntity = null;

        for(int i = 0; i < fields.length; ++i) {
            Field field = fields[i];
            if (!PoiPublicUtil.isNotUserExcelUserThis((List)null, field, targetId)) {
                if (!PoiPublicUtil.isJavaClass(field) && !field.getType().isEnum()) {
                    List<Method> newMethods = new ArrayList();
                    if (getMethods != null) {
                        newMethods.addAll(getMethods);
                    }

                    ExcelEntity excel = (ExcelEntity)field.getAnnotation(ExcelEntity.class);
                    newMethods.add(PoiReflectorUtil.fromCache(pojoClass).getSetMethod(field.getName()));
                    this.getExcelFieldList(StringUtils.isNotEmpty(excel.id()) ? excel.id() : targetId, PoiPublicUtil.getClassFields(field.getType()), field.getType(), temp, newMethods);
                }else if (PoiPublicUtil.isCollection(field.getType())) {//添加 pzc 2023年12月27日
                    ExcelCollection excel = (ExcelCollection)field.getAnnotation(ExcelCollection.class);
                    ExcelCollectionParams collection = new ExcelCollectionParams();
                    collection.setName(field.getName());
                    ParameterizedType pt = (ParameterizedType)field.getGenericType();
                    Class<?> clz = (Class)pt.getActualTypeArguments()[0];
                    collection.setType(clz);
                    String collectionName = collection.getName();
                    String collectionNameParent = null;
                    if(temp.get("collectionName")!=null && temp.get("collectionName").getCollectionName()!=null ){
                        collectionNameParent = temp.get("collectionName").getCollectionName();
                        collectionName = collectionNameParent+"_"+collectionName;
                    }
                    excelEntity = new ExcelImportEntity();
                    excelEntity.setCollectionName(collectionName);
                    temp.put("collectionName",excelEntity);//设置一个临时的实体存放colletionName
                    this.getExcelFieldList(StringUtils.isNotEmpty(excel.id()) ? excel.id() : targetId, PoiPublicUtil.getClassFields(clz), clz, temp, (List)null,excelCollection);
                    //循环中当次运行结束不干扰下次运行
                    if(temp.get("collectionName")!=null && temp.get("collectionName").getCollectionName()!=null
                            && temp.get("collectionName").getCollectionName().indexOf("_")>0){
                        excelEntity.setCollectionName(collectionNameParent);
                        temp.put("collectionName",excelEntity);
                    }else{
                    }
                    collection.setExcelParams(temp);
                    collection.setExcelName(PoiPublicUtil.getValueByTargetId(((ExcelCollection)field.getAnnotation(ExcelCollection.class)).name(), targetId, (String)null));
                    this.additionalCollectionName(collection);
                    if(collectionNameParent==null ) {//当前是顶层运行
                        temp.remove("collectionName");
                        //还原collectionName 用于后续处理
                        for(String key :collection.getExcelParams().keySet()){
                            ExcelImportEntity importEntity = collection.getExcelParams().get(key);
                            importEntity.setCollectionName(importEntity.getCollectionName());
                            importEntity.setGroupName(null);
                        }
                        excelCollection.add(collection);
                    }
                } else {
                    this.addEntityToMap(targetId, field, (ExcelImportEntity)excelEntity, pojoClass, getMethods, temp, (ExcelEntity)null);
                }
            }
        }

    }

    public void addEntityToMap(String targetId, Field field, ExcelImportEntity excelEntity, Class<?> pojoClass, List<Method> getMethods, Map<String, ExcelImportEntity> temp, ExcelEntity excelEntityAnn) throws Exception {
        Excel excel = (Excel)field.getAnnotation(Excel.class);
        excelEntity = new ExcelImportEntity();
        excelEntity.setType(excel.type());
        excelEntity.setSaveUrl(excel.savePath());
        excelEntity.setSaveType(excel.imageType());
        excelEntity.setReplace(excel.replace());
        excelEntity.setEnumImportMethod("merge_"+excel.needMerge());//todo:占用了枚举导入的字段
        excelEntity.setDatabaseFormat(excel.databaseFormat());
        excelEntity.setSuffix(excel.suffix());
        excelEntity.setImportField(Boolean.valueOf(PoiPublicUtil.getValueByTargetId(excel.isImportField(), targetId, "false")));
        excelEntity.setFixedIndex(excel.fixedIndex());
        excelEntity.setName(PoiPublicUtil.getValueByTargetId(excel.name(), targetId, (String)null));
        if (StringUtils.isNoneEmpty(new CharSequence[]{excel.groupName()})) {
            excelEntity.setName(excel.groupName() + "_" + excelEntity.getName());
        }

        if (excelEntityAnn != null && excelEntityAnn.show()) {
            excelEntity.setName(excelEntityAnn.name() + "_" + excelEntity.getName());
        }

        if (this.i18nHandler != null) {
            excelEntity.setName(this.i18nHandler.getLocaleName(excelEntity.getName()));
        }

        excelEntity.setMethod(PoiReflectorUtil.fromCache(pojoClass).getSetMethod(field.getName()));
        if (StringUtils.isNotEmpty(excel.importFormat())) {
            excelEntity.setFormat(excel.importFormat());
        } else {
            excelEntity.setFormat(excel.format());
        }

        excelEntity.setDict(excel.dict());
//        excelEntity.setEnumImportMethod(excel.enumImportMethod());
        if (getMethods != null) {
            List<Method> newMethods = new ArrayList();
            newMethods.addAll(getMethods);
            newMethods.add(excelEntity.getMethod());
            excelEntity.setMethods(newMethods);
        }
        excelEntity.setClassType(pojoClass.getTypeName());
        if(temp.get("collectionName")!=null){
            ExcelImportEntity excelImportEntity = temp.get("collectionName");
            excelEntity.setCollectionName(excelImportEntity.getCollectionName());
            excelEntity.setGroupName(excelImportEntity.getCollectionName());//临时存放
        }

        if (excelEntity.getFixedIndex() != -1) {
            temp.put("FIXED_" + excelEntity.getFixedIndex(), excelEntity);
        } else {
            temp.put(excelEntity.getName(), excelEntity);
        }

    }

    private void additionalCollectionName(ExcelCollectionParams collection) {
        Set<String> keys = new HashSet();
        keys.addAll(collection.getExcelParams().keySet());
        Iterator var3 = keys.iterator();

        while(var3.hasNext()) {
            String key = (String)var3.next();
            if(!key.equals("collectionName")) {
                if (
//                        collection.getType().getTypeName().equals(collection.getExcelParams().get(key).getClassType())
//                        ||
                        (collection.getExcelParams().get(key).getCollectionName() != null &&
                        collection.getExcelParams().get(key).getCollectionName().endsWith( collection.getName()))) {
                    collection.getExcelParams().put(collection.getExcelName() + "_" + key, collection.getExcelParams().get(key));
                    //去掉尾部集合属性名 递归调用时才能endwith判断为是添加前缀excel标题
                    if (collection.getExcelParams().get(key).getCollectionName() != null &&
                            collection.getExcelParams().get(key).getCollectionName().endsWith( collection.getName())) {
                        String colectionName = collection.getExcelParams().get(key).getCollectionName();
                        if(colectionName.indexOf("_")>0)
                        collection.getExcelParams().get(key).setCollectionName(
                                colectionName.replace("_" + collection.getName(), ""));
                        else
                            collection.getExcelParams().get(key).setCollectionName(
                                    colectionName.replace(  collection.getName(), ""));
                    }
                    collection.getExcelParams().remove(key);
                }
            }
        }

    }
}